package org.jeecg.modules.jx.Interceptor;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.util.Enumeration;
import java.util.Map;
import java.util.UUID;


/**
 * 参考链接：https://juejin.cn/post/7186949393222729784
 */
@Slf4j
//@Component
public class CommonHttpInterceptor  implements HandlerInterceptor {

    private static final String UNKNOWN = "unknown";
    private static final String MONITOR_HEALTH = "/monitor/health";

    long start = 0;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String requestId = "requestId-" + UUID.randomUUID().toString();

        start = System.currentTimeMillis();
        String url = request.getRequestURL().toString();
        // 接口过滤打印
        if (url.contains(MONITOR_HEALTH)) {
            return true;
        }

        String method = request.getMethod();
        String queryString = "";
        // 去掉最后一个空格
        Map<String, String[]> params = request.getParameterMap();
        for (String key : params.keySet()) {
            String[] values = params.get(key);
            for (String value : values) {
                queryString += key + "=" + value + "&";
            }
        }
        // URL 参数, substring(0, queryString.length() - 1) 是为了删除前面for循环时，多拼接的 & 字符
        queryString = "".equals(queryString) ? null : queryString.substring(0, queryString.length() - 1);

        // body 参数
        BufferedReader bufferedReader = request.getReader();
        String requestBody = "";
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
            requestBody += line;
        }

        // header参数
        JSONObject headers = new JSONObject();
        Enumeration<String> headerNames = request.getHeaderNames();
        while(headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            headers.put(headerName, headerValue);
        }

        // 公网IP
        String cIp = CommonHttpInterceptor.getIpAddress(request);

        log.info("{} 应用请求参数 url: {}",requestId, url);
        log.info("{} method: {}", requestId, method);
        log.info("{} query-params: {}", requestId, queryString);
        log.info("{} request-body: {}", requestId, requestBody);
        log.info("{} headers-params: {}", requestId, headers);
        log.info("{} c-ip: {}", requestId, cIp);
        request.setAttribute("requestId", requestId);

        return true;
    }

    /**
     * 获取用户真实IP地址
     *
     * @param request 请求参数
     * @return ip地址
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        //不管转发多少次，取第一位
        String remoteIp = ip.split(",")[0];
        MDC.put("remote_ip", remoteIp);
        return remoteIp;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long end = System.currentTimeMillis();
        String requestId = (String)request.getAttribute("requestId");
        log.info("requestId: {}, run time: {}", requestId, (end - start) );
    }
}
